

package cn.jh.common.core.json;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.TypeUtils;
import com.google.common.base.Charsets;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;

import static com.google.common.base.Preconditions.checkArgument;


/**
 * @author Fuchun
 * @since 1.0
 */
public class FastJsonOperator extends AbstractJsonOperator {

    @Override
    public String toJSONString(Object object, Class<?> viewClass, boolean prettyPrinter) {
        return com.alibaba.fastjson.JSON.toJSONString(object, prettyPrinter);
    }

    @Override
    public byte[] toJSONBytes(Object object, Class<?> viewClass) {
        return com.alibaba.fastjson.JSON.toJSONBytes(object);
    }

    @Override
    public void writeValue(OutputStream output, Object object) throws IOException {
        writeValue(output, object, false);
    }

    @Override
    public void writeValue(OutputStream output, Object object, boolean prettyPrinter) throws IOException {
        SerializerFeature[] features = prettyPrinter ? new SerializerFeature[] {
                SerializerFeature.PrettyFormat } : new SerializerFeature[0];
        com.alibaba.fastjson.JSON.writeJSONString(output, Charsets.UTF_8, object, features);
    }

    @Override
    @SuppressWarnings("TypeParameterUnusedInFormals")
    public <T> T convert(Map<String, Object> map, Type type) {
        if (map == null) return null;
        return TypeUtils.cast(map, type, ParserConfig.getGlobalInstance());
    }

    @Override
    protected <T> T doConvert(Map<String, Object> map, Class<T> targetClass) {
        return TypeUtils.cast(map, targetClass, ParserConfig.getGlobalInstance());
    }

    @Override
    public <T> T parseObject(String jsonString, Class<T> targetClass) {
        return com.alibaba.fastjson.JSON.parseObject(jsonString, targetClass);
    }

    @Override
    @SuppressWarnings("TypeParameterUnusedInFormals")
    public <T> T parseObject(String jsonString, Type type) {
        return com.alibaba.fastjson.JSON.parseObject(jsonString, type);
    }

    @Override
    public <T> T parseObject(File file, Class<T> targetClass) throws IOException {
        return parseObject(file, (Type) targetClass);
    }

    @Override
    @SuppressWarnings("TypeParameterUnusedInFormals")
    public <T> T parseObject(File file, Type targetType) throws IOException {
        checkArgument(file != null && file.exists(), "The file must be not null and exists.");
        checkArgument(file.isFile(), "The file is a directory?");
        return parseObject(new FileInputStream(file), targetType);
    }

    @Override
    public <T> T parseObject(InputStream input, Class<T> targetClass) throws IOException {
        return com.alibaba.fastjson.JSON.parseObject(input, targetClass);
    }

    @Override
    @SuppressWarnings("TypeParameterUnusedInFormals")
    public <T> T parseObject(InputStream input, Type targetType) throws IOException {
        return com.alibaba.fastjson.JSON.parseObject(input, targetType);
    }

    //    @Override
//    protected <C extends Collection<?>, T> C doParseToCollection(
//            String jsonString, Class<C> listClass, Class<T> elementClass) {
//        Type type = new TypeToken<C>() {}
//                .where(new TypeParameter<T>() {}, elementClass).getType();
//        return com.alibaba.fastjson.JSON.parseObject(jsonString, type);
//    }

    @Override
    @SuppressWarnings("unchecked")
    protected <C extends Collection<T>, T> C doParseToCollection(
            String jsonString, Class<C> listClass, Type elementType) {
        TypeToken<C> typeToken = TypeToken.of(listClass);
        return com.alibaba.fastjson.JSON.parseObject(jsonString, typeToken.getType());
    }

    @Override
    protected <K, V, M extends Map<K, V>> M doParseToMap(
            String jsonString, Class<M> mapClass, Class<K> keyClass, Class<V> valueClass) {
        Type type = TypeToken.of(mapClass).getType();
        return com.alibaba.fastjson.JSON.parseObject(jsonString, type);
    }

    @Override
    @SuppressWarnings("unchecked")
    protected <K, V> Map<K, V> doParseToMap(String jsonString, Type keyType, Type valueType) {
        TypeToken<K> keyTypeToken = (TypeToken<K>) TypeToken.of(keyType);
        TypeToken<V> valueTypeToken = (TypeToken<V>) TypeToken.of(valueType);
        Type type = new TypeToken<Map<K, V>>() {}
                .where(new TypeParameter<K>() {}, keyTypeToken)
                .where(new TypeParameter<V>() {}, valueTypeToken)
                .getType();
        return com.alibaba.fastjson.JSON.parseObject(jsonString, type);
    }
}
